{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "IJulia.set_verbose()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Manual Test Notebook\n",
    "\n",
    "Run each cell, check for expected behaviour and check the browser console for errors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "using Interact"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "#Dependent sliders\n",
    "# move the sin slider (before moving x): the first number below the widgets (signal(first_slider)) \n",
    "# should update, but should stop after you move the x slider\n",
    "# second and third (sval and cval) should update if x is moved, and if sin or cos slider is moved respectively\n",
    "# moving the x should also move the sliders\n",
    "\n",
    "x = slider(0:.1:2pi, label=\"x\")\n",
    "s = map(a -> slider(-1:.05:1, value=sin(2a), label=\"sin(2x)\"), signal(x))\n",
    "c = map(a -> slider(-1:.05:1, value=cos(2a), label=\"cos(2x)\"), signal(x))\n",
    "sval = flatten(map(w->signal(w), signal(s); typ=Signal); typ=Any)\n",
    "cval = flatten(map(w->signal(w), signal(c); typ=Signal); typ=Any)\n",
    "first_slider = value(s)\n",
    "map(display, [x,s,c,signal(first_slider), sval, cval]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#Signal{Widget} display, updating - move the slider, click \"checkbox\", click the checkbox - stuff should update\n",
    "widget_choice = togglebuttons([\"slider\",\"checkbox\"], label=\"choose a widget\")\n",
    "slider_to_show = slider(1:10; label=\"killr slider\")\n",
    "checkbox_to_show = checkbox(true; label=\"my new checkcheck\")\n",
    "widget_chosen = map(x->x==\"slider\"? slider_to_show : checkbox_to_show, signal(widget_choice); typ=Widget);\n",
    "\n",
    "map(display, (widget_choice, widget_chosen, signal(checkbox_to_show), signal(slider_to_show)));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#these should be in sync with the above, but disappear when you click the widget selector above\n",
    "map(display, (checkbox_to_show, slider_to_show));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#Same again but creating a new slider each time, plus flatten\n",
    "count = 0\n",
    "widget_choice = togglebuttons([\"slider\",\"checkbox\"], label=\"choose a widget\")\n",
    "widget_chosen = map(signal(widget_choice); typ=Widget) do x\n",
    "    global count += 1; \n",
    "    x==\"slider\"? slider(1:10; label=\"killr slider $count\") : checkbox(true; label=\"my new checkcheck $count\") \n",
    "end;\n",
    "\n",
    "chosen_val = flatten(map(w->signal(w), widget_chosen; typ=Signal); typ=Any)\n",
    "map(display, (widget_choice, widget_chosen, chosen_val));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "#check sync as above\n",
    "chosen_val = flatten(map(w->signal(w), widget_chosen; typ=Signal); typ=Any)\n",
    "map(display, (widget_choice, widget_chosen, chosen_val));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#Signal{Widget} with same Widget type\n",
    "#buttons sometimes out of order is ipywidgets issue\n",
    "eb=togglebuttons([1,2,3])\n",
    "display(eb)\n",
    "uuid=[[0,1],[0,1,2],[0,2]]\n",
    "ub = map(x->togglebuttons(uuid[x]),eb.signal)\n",
    "ub40 = flatten(map(w->signal(w), signal(ub); typ=Signal); typ=Any)\n",
    "display.([ub, ub40]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#Slider options: vertical, no readout \n",
    "s1 = vslider(-1:.05:1, value=sin(2), label=\"vert\")\n",
    "s2 = slider(-1:.05:1, value=sin(2), label=\"no readout\", signal=signal(s1), orientation=\"horizontal\", readout=false)\n",
    "display.([s1,s2]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "pboy = progress() #should show all grey, then some colour when you run the cell below"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "update!(pboy,50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Select Slider with value set via textbox, type 9, 99, 999, 9999\n",
    "# Value should be the value from the textbox, changes in slider should update teh textbox and vice-versa \n",
    "\n",
    "exprange = map(x->2^x,1:0.01:10)\n",
    "init_val = first(exprange)\n",
    "\n",
    "#create slider\n",
    "expslide = selection_slider(exprange, label=\"exponential value\")\n",
    "\n",
    "#create textbox\n",
    "txtbox = textbox(string(init_val); label=\"set slider value\")\n",
    "nearest(arr, val) = indmin(abs(val .- arr))\n",
    "\n",
    "#holds the last valid float value of what's in the textbox\n",
    "output_valsig = foldp(init_val, signal(txtbox)) do prev, txt\n",
    "    val = tryparse(Float64, txt)\n",
    "    isnull(val) ? prev : get(val)\n",
    "end\n",
    "\n",
    "#find the nearest value to what's in the textbox, and update the slider's signal with it \n",
    "map(output_valsig) do val\n",
    "    idx = nearest(exprange, val)\n",
    "    if value(signal(expslide)) != exprange[idx]\n",
    "        push!(signal(expslide), exprange[idx])\n",
    "    end\n",
    "end |> preserve\n",
    "\n",
    "#if the slider moves, update the txt box\n",
    "map(signal(expslide)) do sliderval\n",
    "    if nearest(exprange, value(output_valsig)) != nearest(exprange, sliderval)\n",
    "        push!(signal(txtbox), string(sliderval))\n",
    "    end\n",
    "end |> preserve\n",
    "\n",
    "#display the widgets and the slider's signal's value\n",
    "display.([expslide, txtbox, signal(expslide), signal(txtbox), signal(output_valsig)]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "push!(signal(expslide), 30) #should update textbox and slider"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "push!(signal(txtbox), \"50\") #should update textbox and slider"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Same but vertical selection_slider, Float64 textbox, shared signal, and textbox value set.\n",
    "# Value should be the value from the textbox, changes in slider should update the textbox and vice-versa \n",
    "\n",
    "expslide = selection_slider(2.^(1:0.01:10), label=\"exponential value\"; orientation=\"vertical\")\n",
    "valsig = signal(expslide)\n",
    "txtbox = textbox(30.0; label=\"entired desired value\", signal=valsig)\n",
    "display.([expslide, txtbox, valsig]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# multi-select - ctrl/cmd or shift click for multiple values\n",
    "mse = selection(enumerate([\"fred\",2,1 + 0.5im, 0.3]) |> collect, multi=true)\n",
    "ms = selection([\"fred\",2,1 + 0.5im, 0.3], multi=true)\n",
    "abc = selection([(\"a\",1), (\"b\",2), (\"c\",3)]; multi=true)\n",
    "display.([ms,signal(ms)]);\n",
    "display.([mse,signal(mse)]);\n",
    "display.([abc,signal(abc)]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#single select\n",
    "ss = selection(11:20)\n",
    "display.([ss,signal(ss)]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Update options value_label displayed by pushing value to signal, by running cell below\n",
    "# n.b. labels should just be \"kHz\", \"MHz\", \"GHz\", not \"kHz=>1e6\"\n",
    "fmult = Signal(Float64, 1e9) #GHz\n",
    "w_fmult = togglebuttons([(\"kHz\" => 1e3), (\"MHz\" => 1e6), (\"GHz\" => 1e9)], value=value(fmult), signal=fmult)\n",
    "display.([w_fmult, signal(w_fmult)]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#run this multiple times, val should match selected toggle button\n",
    "val = rand([1e3,1e6,1e9])\n",
    "push!(fmult, val)\n",
    "val"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Same test but just with tuples rather than pairs\n",
    "fmult = Signal(Float64, 1e9) #GHz\n",
    "w_fmult = togglebuttons([(\"kHz\" , 1e3), (\"MHz\" , 1e6), (\"GHz\" , 1e9)], value=value(fmult), signal=fmult)\n",
    "display.([w_fmult, signal(w_fmult)]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#run this multiple times, val should match selected toggle button\n",
    "val = rand([1e3,1e6,1e9])\n",
    "push!(fmult, val)\n",
    "val"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#slider stays synced with sig, use cell below\n",
    "s4 = slider(12:20)\n",
    "display.([s4, signal(s4)]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#slider above should move to 13\n",
    "push!(signal(s4), 13)\n",
    "update_view(s4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#syncsig=false doesn't stay synced with sig, use cell below\n",
    "s5 = slider(12:20; syncsig=false)\n",
    "display.([s5, signal(s5)]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#slider above *shouldn't* move to 13, but signal value below it should show 13\n",
    "push!(signal(s5), 13)\n",
    "update_view(s5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Print during update - when slider moves should print multiple \"i = x\"\n",
    "@manipulate for i in 1:10\n",
    "    @show i\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#byo signal\n",
    "ss = Signal(3)\n",
    "s1= slider(0:10; signal=ss)\n",
    "map(display, (s1,ss));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#Byo Signal and init value\n",
    "fx = Signal(0.0)\n",
    "x = slider(0:.1:2pi, label=\"x\")\n",
    "y = map(v -> slider(-1:.05:1, value=sin(v), signal=fx, label=\"sin(x)\"), signal(x))\n",
    "#init value only\n",
    "z = map(a -> slider(-1:.05:1, value=sin(2a), label=\"sin(2x)\"), signal(x))\n",
    "ssz = flatten(map(zslider->signal(zslider), signal(z)))\n",
    "sinx = map(xv->round(sin(xv), 3), signal(x))\n",
    "sin2x = map(xv->round(sin(2xv), 3), signal(x))\n",
    "#top 3 values should be the same as the slider readouts after you move x (but not the other 2 sliders)\n",
    "#next two should be ~= sliders 2 and 3 at all times\n",
    "display.([x, y, z, signal(x), sinx, sin2x, fx, ssz]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "using Interact"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#layout hbox vbox - vertical sliders should be side-by-side with the checkbox below slider s1\n",
    "cb = checkbox();\n",
    "s1 = slider(1:10; label=\"s1\", orientation=\"vertical\"); \n",
    "s2 = vslider(11:0.1:20; label=\"s2\");\n",
    "layout = hbox(vbox(s1,cb), s2)\n",
    "display.([layout, map(signal, (cb,s1,s2))...]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#hbox, vbox as values of a signal{Widget} 1\n",
    "# N sets of 4 togglebuttons should appear on one row, where N is the value of the slider\n",
    "n = selection_slider(1:4)\n",
    "s1 = map(nv->hbox(map(nvi->togglebuttons(nvi+10:nvi+13), 1:nv)...), signal(n))\n",
    "display.([n, s1]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# hbox, vbox as values of a signal{Widget} 1, orientation should change from horizontal to\n",
    "# vertical as you move the slider\n",
    "\n",
    "s2 = map(nv->(boxer = nv%2 == 0 ? hbox : vbox; boxer(togglebuttons(nv:nv+3), togglebuttons(nv:nv+3))), signal(n))\n",
    "display.([n, s2]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#sin and cos are types that are subtypes of Function, make sure Options can generalise inputs to be of type Function\n",
    "#clicking the buttons should update the \"sin (generic function with 10 methods)\" output (to \"cos ...\" and back)\n",
    "t = togglebuttons([sin,cos])\n",
    "display.([t, signal(t), eltype(signal(t))])\n",
    "@show typeof.([sin,cos]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#Demo on README, was broken because option Pairs didn't work\n",
    "using Gadfly\n",
    "@manipulate for Φ=0:π/16:4π, f=[:sin => sin, :cos => cos]\n",
    "    plot(θ -> f(θ+Φ ), 0, 25)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# test the set! function, bottom slider should have the range defined by the top 3 sliders\n",
    "sldmin = slider(0:.01:10.0, label=\"min value\")\n",
    "sldstep = slider(0.01:.01:1, label=\"step size\")\n",
    "sldmax = slider(10.0:.1:20.0, label=\"max value\")\n",
    "sldrange = map((vmin, vstep, vmax)->vmin:vstep:vmax, signal(sldmin), signal(sldstep), signal(sldmax))\n",
    "s1 = slider(.01:.5:15.0)\n",
    "set!(s1, :range, sldrange)\n",
    "display.([sldmin, sldstep, sldmax, s1, sldrange]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#latex output, should be replaced and formatted nicely as you ramp up the slider\n",
    "using SymPy\n",
    "x=Sym(\"x\")\n",
    "s = @manipulate for n=vslider(1:50)\n",
    "    SymPy.diff(sin(x^2),x,n)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#make sure the default options index on an empty range is not 0, i.e. this shouldn't error\n",
    "selection_slider(-1:-1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#first click on slider shouldn't show output, only subsequent moves.\n",
    "#i.e. output should be v=3 (initial), then v=4 or v=2 after moving the slider left or right\n",
    "s5 = slider(1:5)\n",
    "display(s5)\n",
    "foreach(v ->(@show v), signal(s5));"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.6.0-rc1",
   "language": "julia",
   "name": "julia-0.6"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
